/**
 * created by 2025-05-08
 * 事件触发器
 */

type EventHandler<T = any> = (data: T) => void;

export class EventTrigger {
    private events: Map<string, Set<EventHandler>> = new Map();

    /**
     * Register an event handler
     * @param eventName The name of the event
     * @param handler The event handler function
     */
    on<T = any>(eventName: string, handler: EventHandler<T>): void {
        if (!this.events.has(eventName)) {
            this.events.set(eventName, new Set());
        }
        this.events.get(eventName)!.add(handler);
    }

    /**
     * Register an event handler that will be called only once
     * @param eventName The name of the event
     * @param handler The event handler function
     */
    once<T = any>(eventName: string, handler: EventHandler<T>): void {
        const onceHandler = (data: T) => {
            handler(data);
            this.off(eventName, onceHandler);
        };
        this.on(eventName, onceHandler);
    }

    /**
     * Remove an event handler
     * @param eventName The name of the event
     * @param handler The event handler function to remove
     */
    off<T = any>(eventName: string, handler: EventHandler<T>): void {
        const handlers = this.events.get(eventName);
        if (handlers) {
            handlers.delete(handler);
            if (handlers.size === 0) {
                this.events.delete(eventName);
            }
        }
    }

    /**
     * Trigger an event with data
     * @param eventName The name of the event
     * @param data The data to pass to the event handlers
     */
    trigger<T = any>(eventName: string, data: T): void {
        const handlers = this.events.get(eventName);
        if (handlers) {
            handlers.forEach(handler => {
                try {
                    handler(data);
                } catch (error) {
                    console.error(`Error in event handler for ${eventName}:`, error);
                }
            });
        }
    }

    /**
     * Clear all handlers for a specific event
     * @param eventName The name of the event to clear
     */
    clear(eventName: string): void {
        this.events.delete(eventName);
    }

    /**
     * Clear all events and their handlers
     */
    clearAll(): void {
        this.events.clear();
    }

    /**
     * Get the number of handlers for a specific event
     * @param eventName The name of the event
     * @returns The number of handlers
     */
    getHandlerCount(eventName: string): number {
        return this.events.get(eventName)?.size || 0;
    }
}